package com.dq.demos.web.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.mychain.gov.sdk.GovDataSDK;
import com.alipay.mychain.gov.sdk.base.DecryptAndVerifyUtils;
import com.alipay.mychain.gov.sdk.base.FileResultZww;
import com.alipay.mychain.gov.sdk.facade.enums.EncryptTpyeEnum;
import com.alipay.mychain.gov.sdk.request.SignedRequest;
import com.dq.demos.web.utils.HttpUtils;
import com.dq.demos.web.utils.ZlbpInterfaceTool;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nuonuo.plate.extracte.BaseExtracte;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.security.Security;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

@RestController
@RequestMapping("/zlb")
public class ZLBController {
    private static Logger logger = LoggerFactory.getLogger(ZLBController.class);
    private static ZlbpInterfaceTool tool = new ZlbpInterfaceTool();

    /**
     * 浙里办发票下载
     *
     * @return
     */
    @RequestMapping("/test")
    public String test() throws Exception {
        return "Success";
    }

    /**
     * 银行对账单下载
     *
     * @return
     */
    @RequestMapping("/downBankRecon")
    @ResponseBody
    public String downBankRecon(@RequestBody Map map) throws Exception {
        String url = map.get("zlbUrl").toString();
        String requestParam = map.get("requestParam").toString();
        return HttpUtils.sendPost(url, requestParam);
    }

    /**
     * 浙里办发票下载
     *
     * @return
     */
    @RequestMapping("/downInvoice")
    public String downLoadInvoice(@RequestBody Map map) throws Exception {
        // 创建ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            // 转换为JSON字符串
            String jsonString = objectMapper.writeValueAsString(map);
            logger.info("发票下载请求参数: " + jsonString);
            System.out.println("发票下载请求参数: " + jsonString);
        } catch (Exception e) {
            return "请求参数:【"+map.toString()+"】格式化异常";
        }
        String url = map.get("zlbUrl").toString();
        String requestParam = map.get("requestParam").toString();
        String downInv = HttpUtils.sendPost(url, requestParam);
        System.out.println("##请求参数:【"+requestParam+"】,浙里办响应:【"+downInv+"】");
        logger.info("##请求参数:【"+requestParam+"】,浙里办响应:【"+downInv+"】");
        return downInv;
    }

    /**
     * 银行回单下载
     *
     * @return
     */
    @RequestMapping("/downBankReceipt")
    public String downBankReceipt(@RequestBody Map map) throws Exception {
        String url = map.get("zlbUrl").toString();
        String startDate = map.get("startDate").toString();
        String endDate = map.get("endDate").toString();
        String idcode = map.get("idcode").toString();
        String mnecode = map.get("mnecode").toString();
        String secretKey = map.get("secretKey").toString();
        String appKey = map.get("appKey").toString();

        Calendar calendar = Calendar.getInstance();
        // 获取 Date 对象
        Date date = calendar.getTime();
        // 创建 SimpleDateFormat 对象，指定日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String srcContent = "{\"startDate\":\"" + startDate + "\",\"endDate\":\"" + endDate + "\",\"type\":0,\"cardNo\":\"" + idcode + "\",\"platformId\": \"" + mnecode + "\"}";
        String requestId = "FFFFFFFFFFFFFFFFF" + "_" + sdf.format(date);
        ;
        String time = sdf.format(date);

        String content = tool.encrypt(secretKey, srcContent);

        String data = content + requestId + time;
        String sign = tool.getSignature(data, secretKey);
        String jsonStr = "{\"requestId\":\"" + requestId + "\",\"appKey\":\"" + appKey + "\",\"time\":\"" + time + "\",\"method\":\"apply_receipt\",\"content\":\"" + content + "\",\"sign\":\"" + sign + "\"}";
        return HttpUtils.sendPost(url, jsonStr);
    }

    /**
     * 银行单据查询
     *
     * @return
     */
    @RequestMapping("/bankBill")
    public String queryBankBill(@RequestBody Map map) throws Exception {
        String url = map.get("zlbUrl").toString();
        String taskId = map.get("taskId").toString();
        String platformId = map.get("platformId").toString();
        String secretKey = map.get("secretKey").toString();
        String appKey = map.get("appKey").toString();
        Calendar calendar = Calendar.getInstance();
        // 获取 Date 对象
        Date date = calendar.getTime();
        // 创建 SimpleDateFormat 对象，指定日期格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        String requestId = "FFFFFFFFFFFFFFFFF" + "_" + sdf.format(date);
        ;
        String time = sdf.format(date);
        String srcContent =
                "{\"taskId\":\"" + taskId + "\",\"platformId\": \"" + platformId + "\"}";

        String content = tool.encrypt(secretKey, srcContent);
        String data = content + requestId + time;
        String sign = tool.getSignature(data, secretKey);
        String jsonStr =
                "{\"requestId\":\"" + requestId + "\",\"appKey\":\"" + appKey + "\",\"time\":\"" + time
                        + "\",\"method\":\"query_receipt\",\"content\":\"" + content + "\",\"sign\":\""
                        + sign + "\"}";
        return HttpUtils.sendPost(url, jsonStr);
    }

    @RequestMapping("/getSign")
    public String getSign(@RequestBody Map map) throws Exception {
        String jsonStr = map.get("jsonStr").toString();
        String instCode = map.get("instCode").toString();
        String privateKeyContent = map.get("privateKeyContent").toString();
        String password = map.get("password").toString();
        SignedRequest request;
        try {
//            Security.addProvider(new BouncyCastleProvider());
            GovDataSDK.getInstance().init(instCode, privateKeyContent, password, EncryptTpyeEnum.SM4);
            request = GovDataSDK.getInstance().getRequestBuilder().generateSignedPayload(jsonStr);
        } catch (Exception e) {
            throw new Exception("#######浙里办签名处理失败:" + e.getMessage());
        }
        return JSON.toJSONString(request);
    }

    @RequestMapping("/downZip")
    public BufferedOutputStream downBankHuiDanZip(@RequestBody Map map, HttpServletResponse response) throws Exception {
        String ZIPurl = map.get("zlbUrl").toString();
        ByteArrayOutputStream baos = null;
        InputStream inputStream = null;
        BufferedOutputStream outputStream = null;
        try {
            String[] split = ZIPurl.split("/");
            URL url = new URL(ZIPurl);
            URLConnection conn = url.openConnection();
            inputStream = conn.getInputStream();
            response.reset();
            //文件类型自动判断
            response.setContentType("multipart/form-data");
            response.setCharacterEncoding("UTF-8");
            //将Content-Disposition暴露给前端
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
            //将文件名放入header的Content-Disposition中
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(split[split.length - 1], "UTF-8"));
            byte[] buffer = new byte[1024 * 1024 * 10];
            int len;
            outputStream = new BufferedOutputStream(response.getOutputStream());
            while ((len = inputStream.read(buffer)) > 0) {
                outputStream.write(buffer, 0, len);
            }
        } catch (Exception e) {
            logger.error("银行回单ZIP" + ZIPurl + "压缩包下载失败:" + e.getMessage());
        } finally {
            if (null != baos) {
                baos.close();
            }
            if (null != outputStream) {
                outputStream.close();
            }
            if (null != inputStream) {
                inputStream.close();
            }
        }
        return outputStream;
    }

    @RequestMapping("/DecryptAndVerify")
    public void decryptAndVerifyUtil(
            @RequestBody Map<String, Object> map, // 泛型指定更清晰，避免强转警告
            HttpServletResponse response) throws Exception {

        // 1. 从请求参数中提取数据（增加非空校验，避免空指针）
        String instCode = String.valueOf(map.getOrDefault("instCode", ""));
        String password = String.valueOf(map.getOrDefault("password", ""));
        String privateKeyContent = String.valueOf(map.getOrDefault("privateKeyContent", ""));
        Map<String, Object> frzmap = (Map<String, Object>) map.getOrDefault("frz", null);

        // 基础参数校验（根据业务需求补充）
        if (frzmap == null) {
            throw new IllegalArgumentException("请求参数中'frz'不能为空");
        }
        if (instCode.isEmpty() || password.isEmpty() || privateKeyContent.isEmpty()) {
            throw new IllegalArgumentException("instCode、password、privateKeyContent不能为空");
        }

        // 2. 初始化工具类并执行解密，获取文件字节数组
        DecryptAndVerifyUtils decryptUtils = new DecryptAndVerifyUtils(instCode, password, privateKeyContent);
        FileResultZww frzww = new FileResultZww();
        frzww.setFileName(frzmap.get("fileName").toString());
        frzww.setLayoutFile(frzmap.get("layoutFile").toString());
        frzww.setEnvelope(frzmap.get("envelope").toString());
        byte[] decryptedFileData = decryptUtils.decryptZww(frzww); // 解密后的文件字节数组
        // 3. 配置响应头，告诉前端这是文件流（核心步骤）
        response.setCharacterEncoding("UTF-8");
        // 设置文件类型：OFD文件的MIME类型（若为其他文件需调整，如PDF为application/pdf）
        response.setContentType("application/octet-stream");
        // 设置响应方式：attachment表示下载，inline表示在线预览（根据需求选择）
        // 文件名建议从frzww.getFileName()获取，避免硬编码
        String fileName = new String(frzww.getFileName().getBytes("UTF-8"), "ISO-8859-1");
        response.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
        // 设置文件大小（可选，帮助前端显示进度）
        response.setContentLength(decryptedFileData.length);
        // 4. 构造 JSON 数据（文件元信息）
        InputStream is = new ByteArrayInputStream(decryptedFileData);
        BaseExtracte baseExtracte = new BaseExtracte();
        JSONObject jsonObject = baseExtracte.readXbrl(is);
        Map<String, Object> jsonData = new HashMap<>();
        jsonData.put("fileName", frzww.getFileName());
        jsonData.put("fileSize", decryptedFileData.length);
        jsonData.put("data", jsonObject);
        jsonData.put("status", "success");
        // 5. 将 JSON 数据写入 HTTP Header（Base64 编码避免特殊字符问题）
        String jsonStr = new ObjectMapper().writeValueAsString(jsonData);
        response.setHeader("X-Metadata", Base64.getEncoder().encodeToString(jsonStr.getBytes(StandardCharsets.UTF_8)));


        // 4. 将解密后的字节数组写入响应流（使用try-with-resources自动关闭流）
        try (OutputStream out = response.getOutputStream()) { // 直接用response的输出流，无需再创建DataOutputStream
            out.write(decryptedFileData); // 一次性写入字节数组（比循环writeByte高效）
            out.flush(); // 强制刷新，确保所有数据发送到前端
        } catch (IOException e) {
            // 捕获IO异常，避免响应中断导致前端一直等待
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            throw new IOException("文件流写入响应失败：" + e.getMessage(), e);
        }
    }
}
